package com.bjpowernode.springboot.service.Impl;

import com.bjpowernode.springboot.dao.StudentMapper;
import com.bjpowernode.springboot.entity.Student;
import com.bjpowernode.springboot.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

@Service
public class StudentServiceImpl implements StudentService {

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate; // 注入redis模板类

    @Autowired
    private StudentMapper studentMapper;

    @Override
    public int saveStudent(Student student) {
        // 创建redis的hash类型的数据结构
        HashOperations<Object, Object, Object> hashOperations = redisTemplate.opsForHash();
        // 将student添加到redis缓存中
        HashMap<Object, Object> studentMap = new HashMap<>();
        // 将Student封装到map中
        ObjectToMap(student,studentMap);
        // 存入redis缓存中
        hashOperations.putAll("student-" + student.getId(),studentMap);
        return 1;
    }


    @Override
    @SuppressWarnings("all")
    public Student getStudent(Integer id) {
        String hashKey = "student-" + id; // 获取hash的key(不是键值对的key)
        HashOperations<Object, Object, Object> hashOperations = redisTemplate.opsForHash();
        Map<Object, Object> entries = hashOperations.entries(hashKey);
        if (entries == null) {
            // 如果hashKey没有对应的键值对返回，说明缓存中不存在，我们需要从数据库中获取，然后放置到缓存中
            Student student = studentMapper.queryStudentById(id);
            // 先判断student是否为空，即数据库中是否存在
            if (student == null) {
                return null;
            }
            // 将student放置在redis缓存中
            saveStudent(student); // 直接调用save方法
            // 返回即可
            return student;
        }
        // 将map中的键值对封装成Student放回
        Student student = new Student();
        MapToObject(student,entries);
        return student;
    }


    @Override
    public String ping() {
        return "pong";
    }


    /**
     * 将Object对象的成员数性封装到map中    反射操作获取类属性
     * @param object
     * @param map
     */
    public void ObjectToMap(Object object , HashMap<Object, Object> map) {
        // 判断Object对象是否是Student的实例或者其子类实例，如果不是直接返回即可
        if (!(object instanceof Student)) {
            return;
        }
        //  此时object是Student实例对象，所以将其强制转化为Student类型
        Student student = (Student) object;
        // 获取Object的Class对象
        Class<? extends Student> clazz = student.getClass();
        Field[] declaredFields = clazz.getDeclaredFields(); // 获取Object的所有类属性字段，包括私有属性
        try {
            for (Field field : declaredFields) {
                field.setAccessible(true); // 设置访问权限，可以访问的状态
                String name = field.getName(); // 获取属性名
                String typeName = field.getGenericType().toString(); // 获取属性的类型
                // 如果是字符串类型
                // 我们通过反射获取其对应的get方法来获取
                // 类的成员属性的对应的get方法的名字格式：getXxxx() Xxxx为属性名首字母需要大写
                name = name.substring(0,1).toUpperCase() + name.substring(1); // 首字母大写，方便后面拼接
                // 获取name对应的get方法
                Method method = clazz.getMethod("get" + name);
                // 调用
                Object invoke = method.invoke(student);
                map.put(name,invoke);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 将Map转化为对象
     */
    public void MapToObject(Student student, Map<Object, Object> entries) {
        for (Object prop : entries.keySet()) {
            if (prop.equals("id")) {
                student.setId((Integer) entries.get(prop));
            } else if (prop.equals("name")) {
                student.setName((String) entries.get(prop));
            } else if (prop.equals("age")) {
                student.setAge((Integer) entries.get(prop));
            }
        }
    }
}
